Step 3 - Long-press to drop a pin

Use the long-press manipulator to enable users to long-press nodes in your Kanzi application. This way you can make the application react when the user presses and holds the pointer pressed on a node for the amount of time you set in the long-press manipulator.

In this step you use the long-press manipulator to enable the user to drop a pin on the map by long-pressing the map. For example, this way you can enable the user to mark a point of interest on the map.

Drop a pin

In this section you create and use the long-press manipulator to drop a pin on the map when the user long-presses the map.

To drop a pin:

  1. In the onProjectLoaded() function, after you get the Map node and before you create the input manipulators, instantiate the Pin prefab as a child of the Map node:
        virtual void onProjectLoaded() KZ_OVERRIDE
        {
            ...
    
            // Get the reference to the prefab template Pin which shows the pin icon.
            ResourceManager* resourceManager = getDomain()->getResourceManager();
            PrefabTemplateSharedPtr pinPrefabTemplate = resourceManager->acquireResource<PrefabTemplate>("kzb://pan_zoom_tap/Prefabs/Pin");
    
            // Instantiate the Pin prefab.
            m_pin = pinPrefabTemplate->instantiate<Node2D>("Pin");
    
            // Add to the Map node the instance of the Pin prefab you created.
            mapNode->addChild(m_pin);
    
            // Disable the Visible property of the Pin prefab instance.
            // You enable the Visible property when the user drops a pin.
            m_pin->setVisible(false);
    
            ...
        }
    
    private:
    
        ...
    
        // Define a member variable for the Pin prefab instance.
        Node2DSharedPtr m_pin;
    };
    
  2. In the private section of the PanZoomTap class define the handler for the long-press message:
        // Define the handler for the LongPressManipulator::LongPressMessage message from the nodes 
        // that have an input manipulator which generates the long-press message.
        void onLongPress(LongPressManipulator::LongPressMessageArguments& messageArguments)
        {
            // Get from the message arguments the node that the user long-presses.
            Node2DSharedPtr mapNode = dynamic_pointer_cast<Node2D>(messageArguments.getSource());
    
            // Get the point where the user long-pressed.
            Vector2 pointerPosition = messageArguments.getPoint();
    
            // Create a render transformation that contains the translation to the point where the user long-pressed.
            SRTValue2D pinSRT = SRTValue2D::createTranslation(pointerPosition);
    
            // Position the tip of the pin where the user long-pressed.
            pinSRT.setTranslation(pinSRT.getTranslation() - Vector2(m_pin->getActualWidth() * 0.5f, m_pin->getActualHeight() * 0.8f));
    
            // Apply the transformation to the Pin prefab instance.
            m_pin->setRenderTransformation(pinSRT);
    
            // Enable the Visible property of the Pin prefab instance.
            m_pin->setVisible(true);
        }
  3. In the onProjectLoaded() function create a LongPressManipulator manipulator and subscribe to its message at the Map node:
        virtual void onProjectLoaded() KZ_OVERRIDE
        {
            ...
    
            // Create an input manipulator that generates the long-press message.
            LongPressManipulatorSharedPtr longPressManipulator = LongPressManipulator::create(domain);
    
            // Add the input manipulator to the Map node.
            mapNode->addInputManipulator(longPressManipulator);
    
            // Set the duration of the long press to 400 ms. The long-press manipulator
            // recognizes the gesture when the user presses the node for this amount of time.
            // The default duration is 500 ms.
            longPressManipulator->setPressDuration(chrono::milliseconds(400));
    
            // Subscribe to the LongPressManipulator::LongPressMessage message at the Map node.
            // The LongPressManipulator manipulator generates this message when the user presses the node
            // for the amount of milliseconds you set in the LongPressManipulator::setPressDuration function.
            mapNode->addMessageHandler(LongPressManipulator::LongPressMessage, bind(&PanZoomTap::onLongPress, this, placeholders::_1));
        }
    
  4. Build and run your application.
    In the application long-press anywhere on the map to drop a pin.

Keep the size and orientation of the dropped pin

When the user zooms and rotates the map, the dropped pin changes size and rotates with the map. This is because you instantiated the Pin prefab, which shows the pin, as a child of the Map node. In this section you add the code to keep the size and orientation of the pin constant.

To keep the size and orientation of the dropped pin:

  1. In the private section of the PanZoomTap class create a function which updates the scale and rotation of the dropped pin based on the scale and rotation of the Map node:
        // Update the scale and rotation of the Pin prefab instance.
        void updatePinScaleAndRotation(SRTValue2D mapSRT, SRTValue2D pinSRT)
        {
            // Set the rotation to be the negative of the rotation of the Map node.
            pinSRT.setRotation(-mapSRT.getRotation());
    
            // Set the scale to be the inverse of the scale of the Map node.
            pinSRT.setScale(componentWiseDivide(Vector2(1.0f, 1.0f), mapSRT.getScale()));
    
            // Apply the render transformation to the Pin prefab instance.
            m_pin->setRenderTransformation(pinSRT);
        }
  2. In the onLongPress function that you added in the previous section, first get the render transformation of the Map node, then call the updatePinScaleAndRotation function.
    This way you keep the size and orientation of the Pin the same regardless of the zoom level and rotation of the Map node.
    Replace
            // Apply the transformation to the Pin prefab instance.
            m_pin->setRenderTransformation(pinSRT);
    with
            // Get the Render Transformation property of the Map node.
            SRTValue2D mapSRT = mapNode->getRenderTransformation();
    
            // Update the scale and position of the Pin prefab instance.
            updatePinScaleAndRotation(mapSRT, pinSRT);
    
  3. In the end of the onPinchMoved function that you created in step 2 of this tutorial, update the scale and rotation of the dropped pin when the user zooms and rotates the map:
        void onPinchMoved(PinchManipulator::MovedMessageArguments& messageArguments)
        {
            ...
    
            // Get the Render Transformation property of the Pin prefab instance.
            SRTValue2D pinSRT = m_pin->getRenderTransformation();
    
            // Update the scale and position of the Pin prefab instance.
            updatePinScaleAndRotation(mapWorldSRT, pinSRT);
        }
  4. In the end of the onNodeDoubleTapped function that you created in step 2 of this tutorial, reset the scale and rotation of the dropped pin when the user double-taps the map:
        void onNodeDoubleTapped(MultiClickManipulator::MultiClickMessageArguments& messageArguments)
        {
            ...
    
            // Reset the rotation and scale of the Pin prefab instance.
            SRTValue2D pinSRT = m_pin->getRenderTransformation();
            pinSRT = SRTValue2D(Vector2(1.0f, 1.0f), 0, pinSRT.getTranslation());
            m_pin->setRenderTransformation(pinSRT);
        }
  5. Build and deploy the application to your Android device.
    When you zoom and rotate the map, the pin that you dropped maintains its size and orientation.


< PREVIOUS STEP

What's next?

In this tutorial you learned how to use the Kanzi input manipulators to enable panning, zooming, rotating, resetting the position, and dropping a pin on the map. Now you can:

See also

To learn more about the long-press manipulator, see Using the long-press manipulator.

To learn how to deploy your Kanzi application to different platforms, see Deploying Kanzi applications.